const util = require('util')
const fs = require('fs')
const path = require('path')

// util.promisify() 把原来的异步回调方法改成返回 Promise 实例的方法, 可以使用await实现异步
const mkdirAsync = util.promisify(fs.mkdir) // 以异步的方式创建文件目录。如果目录已存在，将抛出异常
const readdirAsync = util.promisify(fs.readdir) // 异步获取当前目录的所有文件
const statAsync = util.promisify(fs.stat) //  读取文件的状态

// 创建文件夹
async function createFolder(dirPath) {
	return await mkdirAsync(dirPath)
}

var copyFile = function(srcPath, tarPath, cb) {
	var rs = fs.createReadStream(srcPath) // 将内容读取到内存中，而内存就是Buffer对象
	rs.on('error', function(err) {
		if (err) {
			console.log('read error', srcPath)
		}
		cb && cb(err)
	})

	var ws = fs.createWriteStream(tarPath)
	ws.on('error', function(err) {
		if (err) {
			console.log('write error', tarPath)
		}
		cb && cb(err)
	})
	ws.on('close', function(ex) {
		cb && cb(ex)
	})

	rs.pipe(ws) // 将读到文档流写入指定位置
}

// 递归遍历文件夹内容，复制excludeDirs之外的文件和文件夹
async function copyFolderCore(srcDir, excludeDirs, tarDir, cb, cbError) {
	try {
		const files = await readdirAsync(srcDir)
		var count = 0		
		const checkEnd = function() {
			++count == files.length && cb && cb()
		}

		files.forEach(async (file) => {
			const srcPath = path.join(srcDir, file)
			const tarPath = path.join(tarDir, file)

			const stats = await statAsync(srcPath)

			// 判断是否是文件夹，如果文件夹则递归复制
			if (stats.isDirectory()) {
				if (excludeDirs.indexOf(srcPath) === -1) {
					await createFolder(tarPath)
					await copyFolderCore(srcPath, excludeDirs, tarPath, checkEnd, cbError)
				} else { // 不复制的文件夹
					checkEnd()
				}
			} else {
				copyFile(srcPath, tarPath, checkEnd)
			}
		})
	} catch(error) {
		cbError(error)
	}
}

// 赋值文件夹的所有内容
async function copyFolder(srcDir, excludeDirs, tarDir) {
	return new Promise((resolve, reject) => {
		copyFolderCore(srcDir, excludeDirs, tarDir, resolve, reject)
	}) 
}

module.exports = {
	createFolder: createFolder,
	copyFile: copyFile,
	copyFolder: copyFolder
}
